//go:build windows

package guarderlib

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"github.com/gorpher/gowin32"
	"github.com/shirou/gopsutil/v3/cpu"
	"github.com/shirou/gopsutil/v3/mem"
	"github.com/urfave/cli/v2"
	"miao-client-plugins/base/guarder/session_notifications"
	"os"
	"time"
)

type GuarderServicePlugin struct {
}

func (p GuarderServicePlugin) SayHi() {
	fmt.Println("guarder service plugin say hi")
}
func NewIdpServicePlugin() GuarderServicePlugin {
	return GuarderServicePlugin{}
}

var (
	BuildTime string
	Version   = "1.0.0"
)

func Do() {
	app := cli.NewApp()
	plu := NewIdpServicePlugin()
	app.Name = "idp-guarder-cli"
	app.Version = fmt.Sprintf("%s build:%s", Version, BuildTime)
	app.Usage = "为 idp 提供持续监听服务"
	app.Description = "监听范围包括：内存、cpu的使用情况、windows会话变化情况、设备在线时常等"
	app.Flags = []cli.Flag{
		&cli.Float64Flag{
			Name:        "cpu",
			Aliases:     []string{"c"},
			Usage:       "CPU默认阈值，",
			DefaultText: "0.9",
		},
		&cli.Float64Flag{
			Name:        "memory",
			Aliases:     []string{"m"},
			Usage:       "内存默认阈值，",
			DefaultText: "0.9",
		},
		&cli.IntFlag{
			Name:        "time",
			Aliases:     []string{"t"},
			Usage:       "采集间隔",
			Value:       60,
			DefaultText: "60",
		},
	}
	app.Action = func(ctx *cli.Context) error {
		var (
			preCpu    float64
			preMemory float64
		)
		preCpu = ctx.Float64("cpu")
		if preCpu == 0 {
			preCpu = 0.9
		}
		preMemory = ctx.Float64("memory")
		if preMemory == 0 {
			preMemory = 0.9
		}
		t := ctx.Int("time")
		go func() {
			ticker := time.NewTicker(time.Duration(t) * time.Second)
			for range ticker.C {
				mf, err := plu.listenMemory()
				if err != nil {
					mf = -1
				}
				if mf > preMemory {
					// 封装为结构体返回数据
					msg := MemoryMsg{
						Threshold: preMemory,
						Sample:    mf,
					}
					var mbs1 []byte
					if mbs1, err = json.Marshal(msg); err != nil {
						break
					}
					r := ResultMsg{
						MsgType: "memory",
						Result:  string(mbs1),
					}
					var mbs []byte
					if mbs, err = json.Marshal(r); err != nil {
						break
					}
					w := bufio.NewWriter(os.Stdout)
					//w.WriteString(string(bs) )
					w.Write(mbs)
					w.WriteString("\n")
					w.Flush()
				}
				////////////////////////
				//f, err := plu.listenCpu(1)
				//if err != nil {
				//	f = -1
				//}
				//if f > preCpu {
				//	// 封装为结构体返回数据
				//	csg := CpuMsg{
				//		Threshold:  preCpu,
				//		Sample:     f,
				//		SampleTime: 10,
				//	}
				//	var bs []byte
				//	if bs, err = json.Marshal(csg); err != nil {
				//		break
				//	}
				//	r := ResultMsg{
				//		MsgType: "cpu",
				//		Result:  string(bs),
				//	}
				//	var rbs []byte
				//	if rbs, err = json.Marshal(r); err != nil {
				//		break
				//	}
				//	w := bufio.NewWriter(os.Stdout)
				//	//w.WriteString(string(bs) )
				//	w.Write(rbs)
				//	w.WriteString("\n")
				//	w.Flush()
				//}

			}
		}()
		plu.listenWinSessionChange(ctx.Context)
		for {
			select {
			case <-ctx.Done():
				return nil

			}
		}
	}
	if err := app.Run(os.Args); err != nil {
		fmt.Printf("命令行调用错误：%s ，请查看帮助文档", err.Error())
	}
}

func (p GuarderServicePlugin) listenWinSessionChange(ctx context.Context) {
	chanMessages := make(chan session_notifications.Message, 100)
	session_notifications.Subscribe(chanMessages, ctx)
	go func() {
		for {
			select {
			case <-ctx.Done():
				return
			case m := <-chanMessages:
				var msg WinSessionChangeMsg
				uname, err := callWTS(m.LParam)
				if err != nil {
					break
				}
				msg.SessionId = m.LParam
				msg.Username = uname
				msg.WtsCode = m.WParam
				switch m.UMsg {
				case session_notifications.WM_WTSSESSION_CHANGE:
					switch m.WParam {
					case session_notifications.WTS_CONSOLE_CONNECT:
						msg.Describe = "WTS_CONSOLE_CONNECT：标识的会话已连接"
					case session_notifications.WTS_CONSOLE_DISCONNECT:
						msg.Describe = "WTS_CONSOLE_DISCONNECT：标识的会话已断开连接"
					case session_notifications.WTS_REMOTE_CONNECT:
						msg.Describe = "WTS_REMOTE_CONNECT：标识的会话已连接到远程终端"
					case session_notifications.WTS_REMOTE_DISCONNECT:
						msg.Describe = "WTS_REMOTE_DISCONNECT：标识的会话已与远程终端断开连接"
					case session_notifications.WTS_SESSION_LOGON:
						msg.Describe = "WTS_SESSION_LOGON：用户已登录到标识的会话"
					case session_notifications.WTS_SESSION_LOGOFF:
						msg.Describe = "WTS_SESSION_LOGOFF：用户已注销标识的会话"
					case session_notifications.WTS_SESSION_LOCK:
						msg.Describe = "WTS_SESSION_LOCK：标识的会话已被锁定"
					case session_notifications.WTS_SESSION_UNLOCK:
						msg.Describe = "WTS_SESSION_UNLOCK：标识的会话已解锁"
					case session_notifications.WTS_SESSION_REMOTE_CONTROL:
						msg.Describe = "WTS_SESSION_REMOTE_CONTROL：标识的会话已更改其远程控制状态"
					}
				case session_notifications.WM_QUERYENDSESSION:
					msg.Describe = "WM_QUERYENDSESSION：不知道具体含义的状态，需要排查"
				}
				var bs []byte
				if bs, err = json.Marshal(msg); err != nil {
					return
				}
				r1 := ResultMsg{
					MsgType: "session",
					Result:  string(bs),
				}
				var b1 []byte
				if b1, err = json.Marshal(r1); err != nil {
					return
				}
				w := bufio.NewWriter(os.Stdout)
				w.WriteString(string(b1) + "\n")
				w.Flush()
				close(m.ChanOk)
			}
		}
	}()
}

func (p GuarderServicePlugin) listenCpu(s int) (pre float64, err error) {
	// todo windows 任务管理器中的CPU使用率不知道是怎么计算出来的，尝试过很多种方法都得不到和他相近的值
	// 猜测windows应该有一套机制，将CPU使用率超过阈值的进程CPU使用率标记为最小 0.1%，低于阈值的标记为 0%，然后将取余后的数据累加得到最终结果
	// 无法证明这个事，占时搁置该功能
	c2, err := cpu.Percent(time.Duration(s), false)
	if err != nil {
		return 0, err
	}
	return c2[0], err
}

func (p GuarderServicePlugin) listenMemory() (memPer float64, err error) {
	vs, err := mem.VirtualMemory()
	if err != nil {
		return
	}
	memPer = vs.UsedPercent
	if memPer < 1.0 {
		memPer = 1.0
	}
	// 需要除100才能得到小数
	memPer = memPer / 100.0
	return
}

func callWTS(sessionId int) (string, error) {
	wtsServer := gowin32.OpenWTSServer("")
	return wtsServer.QuerySessionUserName(uint(sessionId))
}
